.macro mte_set_kernel_gcr, tmp, tmp2
 #ifdef CONFIG_KASAN_HW_TAGS
-alternative_if_not ARM64_MTE
+alternative_cb kasan_hw_tags_enable
        b       1f
-alternative_else_nop_endif
+alternative_cb_end
        mov     \tmp, KERNEL_GCR_EL1
        msr_s   SYS_GCR_EL1, \tmp
 1:
        .endm
 
        .macro mte_set_user_gcr, tsk, tmp, tmp2
-#ifdef CONFIG_ARM64_MTE
-alternative_if_not ARM64_MTE
+#ifdef CONFIG_KASAN_HW_TAGS
+alternative_cb kasan_hw_tags_enable
        b       1f
-alternative_else_nop_endif
+alternative_cb_end
        ldr     \tmp, [\tsk, #THREAD_MTE_CTRL]
 
        mte_set_gcr \tmp, \tmp2
 
        task->thread.sctlr_user = sctlr;
 }
 
+static void mte_update_gcr_excl(struct task_struct *task)
+{
+       /*
+        * SYS_GCR_EL1 will be set to current->thread.mte_ctrl value by
+        * mte_set_user_gcr() in kernel_exit, but only if KASAN is enabled.
+        */
+       if (kasan_hw_tags_enabled())
+               return;
+
+       write_sysreg_s(
+               ((task->thread.mte_ctrl >> MTE_CTRL_GCR_USER_EXCL_SHIFT) &
+                SYS_GCR_EL1_EXCL_MASK) | SYS_GCR_EL1_RRND,
+               SYS_GCR_EL1);
+}
+
+void __init kasan_hw_tags_enable(struct alt_instr *alt, __le32 *origptr,
+                                __le32 *updptr, int nr_inst)
+{
+       BUG_ON(nr_inst != 1); /* Branch -> NOP */
+
+       if (kasan_hw_tags_enabled())
+               *updptr = cpu_to_le32(aarch64_insn_gen_nop());
+}
+
 void mte_thread_init_user(void)
 {
        if (!system_supports_mte())
                return;
 
        mte_update_sctlr_user(next);
+       mte_update_gcr_excl(next);
 
        /*
         * Check if an async tag exception occurred at EL1.
        if (task == current) {
                preempt_disable();
                mte_update_sctlr_user(task);
+               mte_update_gcr_excl(task);
                update_sctlr_el1(task->thread.sctlr_user);
                preempt_enable();
        }
 
        return static_branch_likely(&kasan_flag_enabled);
 }
 
-static inline bool kasan_has_integrated_init(void)
+static inline bool kasan_hw_tags_enabled(void)
 {
        return kasan_enabled();
 }
        return IS_ENABLED(CONFIG_KASAN);
 }
 
-static inline bool kasan_has_integrated_init(void)
+static inline bool kasan_hw_tags_enabled(void)
 {
        return false;
 }
 
 #endif /* CONFIG_KASAN_HW_TAGS */
 
+static inline bool kasan_has_integrated_init(void)
+{
+       return kasan_hw_tags_enabled();
+}
+
 #ifdef CONFIG_KASAN
 
 struct kasan_cache {