diff --git a/accel/tcg/internal-common.h b/accel/tcg/internal-common.h
index ec2c6317b7..d900897c6e 100644
--- a/accel/tcg/internal-common.h
+++ b/accel/tcg/internal-common.h
@@ -54,6 +54,8 @@ void cpu_restore_state_from_tb(CPUState *cpu, TranslationBlock *tb,
                                uintptr_t host_pc);
 
 bool tcg_exec_realize_unassigned(CPUState *cpu, Error **errp);
+bool tcg_exec_realize_assigned(CPUState *cpu, Error **errp);
+void tcg_exec_unrealize_assigned(CPUState *cpu);
 void tcg_exec_unrealize_unassigned(CPUState *cpu);
 
 #endif
diff --git a/include/qemu/plugin.h b/include/qemu/plugin.h
index bc5aef979e..d39d105795 100644
--- a/include/qemu/plugin.h
+++ b/include/qemu/plugin.h
@@ -221,12 +221,6 @@ static inline int qemu_plugin_load_list(QemuPluginList *head, Error **errp)
     return 0;
 }
 
-static inline void qemu_plugin_vcpu_init_hook(CPUState *cpu)
-{ }
-
-static inline void qemu_plugin_vcpu_exit_hook(CPUState *cpu)
-{ }
-
 static inline void qemu_plugin_tb_trans_cb(CPUState *cpu,
                                            struct qemu_plugin_tb *tb)
 { }
diff --git a/accel/tcg/cpu-exec-common.c b/accel/tcg/cpu-exec-common.c
index bc9b1a260e..3c4a4c9f21 100644
--- a/accel/tcg/cpu-exec-common.c
+++ b/accel/tcg/cpu-exec-common.c
@@ -56,3 +56,30 @@ void cpu_loop_exit_atomic(CPUState *cpu, uintptr_t pc)
     cpu->exception_index = EXCP_ATOMIC;
     cpu_loop_exit_restore(cpu, pc);
 }
+
+#ifdef CONFIG_PLUGIN
+static void qemu_plugin_vcpu_init__async(CPUState *cpu, run_on_cpu_data unused)
+{
+    qemu_plugin_vcpu_init_hook(cpu);
+}
+#endif
+
+bool tcg_exec_realize_assigned(CPUState *cpu, Error **errp)
+{
+#ifdef CONFIG_PLUGIN
+    cpu->plugin_state = qemu_plugin_create_vcpu_state();
+    /* Plugin initialization must wait until the cpu start executing code */
+    async_run_on_cpu(cpu, qemu_plugin_vcpu_init__async, RUN_ON_CPU_NULL);
+#endif
+
+    return true;
+}
+
+/* undo the initializations in reverse order */
+void tcg_exec_unrealize_assigned(CPUState *cpu)
+{
+#ifdef CONFIG_PLUGIN
+    /* Call the plugin hook before clearing the cpu is fully unrealized */
+    qemu_plugin_vcpu_exit_hook(cpu);
+#endif
+}
diff --git a/accel/tcg/tcg-all.c b/accel/tcg/tcg-all.c
index c08a6acc21..a32663f507 100644
--- a/accel/tcg/tcg-all.c
+++ b/accel/tcg/tcg-all.c
@@ -228,6 +228,8 @@ static void tcg_accel_class_init(ObjectClass *oc, void *data)
     ac->name = "tcg";
     ac->init_machine = tcg_init_machine;
     ac->cpu_common_realize_unassigned = tcg_exec_realize_unassigned;
+    ac->cpu_common_realize_assigned = tcg_exec_realize_assigned;
+    ac->cpu_common_unrealize_assigned = tcg_exec_unrealize_assigned;
     ac->cpu_common_unrealize_unassigned = tcg_exec_unrealize_unassigned;
     ac->allowed = &tcg_allowed;
     ac->gdbstub_supported_sstep_flags = tcg_gdbstub_supported_sstep_flags;
diff --git a/hw/core/cpu-common.c b/hw/core/cpu-common.c
index 0f0a247f56..fda2c2c1d5 100644
--- a/hw/core/cpu-common.c
+++ b/hw/core/cpu-common.c
@@ -30,9 +30,6 @@
 #include "hw/boards.h"
 #include "hw/qdev-properties.h"
 #include "trace.h"
-#ifdef CONFIG_PLUGIN
-#include "qemu/plugin.h"
-#endif
 
 CPUState *cpu_by_arch_id(int64_t id)
 {
@@ -192,13 +189,6 @@ static void cpu_common_parse_features(const char *typename, char *features,
     }
 }
 
-#ifdef CONFIG_PLUGIN
-static void qemu_plugin_vcpu_init__async(CPUState *cpu, run_on_cpu_data unused)
-{
-    qemu_plugin_vcpu_init_hook(cpu);
-}
-#endif
-
 static void cpu_common_realizefn(DeviceState *dev, Error **errp)
 {
     CPUState *cpu = CPU(dev);
@@ -222,14 +212,6 @@ static void cpu_common_realizefn(DeviceState *dev, Error **errp)
         cpu_resume(cpu);
     }
 
-    /* Plugin initialization must wait until the cpu start executing code */
-#ifdef CONFIG_PLUGIN
-    if (tcg_enabled()) {
-        cpu->plugin_state = qemu_plugin_create_vcpu_state();
-        async_run_on_cpu(cpu, qemu_plugin_vcpu_init__async, RUN_ON_CPU_NULL);
-    }
-#endif
-
     /* NOTE: latest generic point where the cpu is fully realized */
 }
 
@@ -237,13 +219,6 @@ static void cpu_common_unrealizefn(DeviceState *dev)
 {
     CPUState *cpu = CPU(dev);
 
-    /* Call the plugin hook before clearing the cpu is fully unrealized */
-#ifdef CONFIG_PLUGIN
-    if (tcg_enabled()) {
-        qemu_plugin_vcpu_exit_hook(cpu);
-    }
-#endif
-
     /* NOTE: latest generic point before the cpu is fully unrealized */
     cpu_exec_unrealizefn(cpu);
 }
