diff --git a/py/compile.c b/py/compile.c
index a38998fdb6668120c248daaf30e499cfe9098b1e..7caa562816143c9e4db223098625c3930e0ce32c 100644
--- a/py/compile.c
+++ b/py/compile.c
@@ -35,6 +35,7 @@
 #include "py/compile.h"
 #include "py/runtime.h"
 #include "py/asmbase.h"
+#include "py/persistentcode.h"
 
 #if MICROPY_ENABLE_COMPILER
 
@@ -78,7 +79,25 @@ typedef enum {
 
 #endif
 
-#if MICROPY_EMIT_NATIVE
+#if MICROPY_EMIT_NATIVE && MICROPY_DYNAMIC_COMPILER
+
+#define NATIVE_EMITTER(f) emit_native_table[mp_dynamic_compiler.native_arch]->emit_##f
+#define NATIVE_EMITTER_TABLE emit_native_table[mp_dynamic_compiler.native_arch]
+
+STATIC const emit_method_table_t *emit_native_table[] = {
+    NULL,
+    &emit_native_x86_method_table,
+    &emit_native_x64_method_table,
+    &emit_native_arm_method_table,
+    &emit_native_thumb_method_table,
+    &emit_native_thumb_method_table,
+    &emit_native_thumb_method_table,
+    &emit_native_thumb_method_table,
+    &emit_native_thumb_method_table,
+    &emit_native_xtensa_method_table,
+};
+
+#elif MICROPY_EMIT_NATIVE
 // define a macro to access external native emitter
 #if MICROPY_EMIT_X64
 #define NATIVE_EMITTER(f) emit_native_x64_##f
@@ -93,6 +112,7 @@ typedef enum {
 #else
 #error "unknown native emitter"
 #endif
+#define NATIVE_EMITTER_TABLE &NATIVE_EMITTER(method_table)
 #endif
 
 #if MICROPY_EMIT_INLINE_ASM
@@ -3470,7 +3490,7 @@ mp_raw_code_t *mp_compile_to_raw_code(mp_parse_tree_t *parse_tree, qstr source_f
                     if (emit_native == NULL) {
                         emit_native = NATIVE_EMITTER(new)(&comp->compile_error, &comp->next_label, max_num_labels);
                     }
-                    comp->emit_method_table = &NATIVE_EMITTER(method_table);
+                    comp->emit_method_table = NATIVE_EMITTER_TABLE;
                     comp->emit = emit_native;
                     break;
 #endif // MICROPY_EMIT_NATIVE
diff --git a/py/emit.h b/py/emit.h
index 2a5da8e8e3933467f427fcf7b8e8287d50b1bb64..7b97372bcbc0b3e989b7e7c3e26f4b6cf20b7a7a 100644
--- a/py/emit.h
+++ b/py/emit.h
@@ -98,6 +98,11 @@ typedef struct _mp_emit_method_table_id_ops_t {
 } mp_emit_method_table_id_ops_t;
 
 typedef struct _emit_method_table_t {
+    #if MICROPY_DYNAMIC_COMPILER
+    emit_t *(*emit_new)(mp_obj_t *error_slot, uint *label_slot, mp_uint_t max_num_labels);
+    void (*emit_free)(emit_t *emit);
+    #endif
+
     void (*start_pass)(emit_t *emit, pass_kind_t pass, scope_t *scope);
     void (*end_pass)(emit_t *emit);
     bool (*last_emit_was_return_value)(emit_t *emit);
diff --git a/py/emitbc.c b/py/emitbc.c
index 4142e892d6e1f935781532fe459e9be7e7c6a494..35eb6df9c0c384904551a1ac3ef9aebdcbd9aed6 100644
--- a/py/emitbc.c
+++ b/py/emitbc.c
@@ -909,6 +909,11 @@ void mp_emit_bc_end_except_handler(emit_t *emit) {
 
 #if MICROPY_EMIT_NATIVE
 const emit_method_table_t emit_bc_method_table = {
+    #if MICROPY_DYNAMIC_COMPILER
+    NULL,
+    NULL,
+    #endif
+
     mp_emit_bc_start_pass,
     mp_emit_bc_end_pass,
     mp_emit_bc_last_emit_was_return_value,
diff --git a/py/emitnative.c b/py/emitnative.c
index aa5ec4935d018f963755588d8f22e3564220e458..da986dc5d96a1b05491c82579ab57d5496bace0c 100644
--- a/py/emitnative.c
+++ b/py/emitnative.c
@@ -2727,6 +2727,11 @@ STATIC void emit_native_end_except_handler(emit_t *emit) {
 }
 
 const emit_method_table_t EXPORT_FUN(method_table) = {
+    #if MICROPY_DYNAMIC_COMPILER
+    EXPORT_FUN(new),
+    EXPORT_FUN(free),
+    #endif
+
     emit_native_start_pass,
     emit_native_end_pass,
     emit_native_last_emit_was_return_value,
diff --git a/py/mpstate.h b/py/mpstate.h
index 98371ca64674baab8625a4d8d3911210d5ca30ab..149660040210a0665b6855b25372492fa7cd5d9e 100644
--- a/py/mpstate.h
+++ b/py/mpstate.h
@@ -46,6 +46,7 @@ typedef struct mp_dynamic_compiler_t {
     uint8_t small_int_bits; // must be <= host small_int_bits
     bool opt_cache_map_lookup_in_bytecode;
     bool py_builtins_str_unicode;
+    uint8_t native_arch;
 } mp_dynamic_compiler_t;
 extern mp_dynamic_compiler_t mp_dynamic_compiler;
 #endif
diff --git a/py/persistentcode.c b/py/persistentcode.c
index ad502a5116623328b73104cf4836a42abd29aed6..70ec2ddd6553d961309232a93d68150206b0f4f5 100644
--- a/py/persistentcode.c
+++ b/py/persistentcode.c
@@ -78,6 +78,12 @@
 #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_NONE)
 #endif
 
+#if MICROPY_DYNAMIC_COMPILER
+#define MPY_FEATURE_ARCH_DYNAMIC mp_dynamic_compiler.native_arch
+#else
+#define MPY_FEATURE_ARCH_DYNAMIC MPY_FEATURE_ARCH
+#endif
+
 #if MICROPY_PERSISTENT_CODE_LOAD || (MICROPY_PERSISTENT_CODE_SAVE && !MICROPY_DYNAMIC_COMPILER)
 // The bytecode will depend on the number of bits in a small-int, and
 // this function computes that (could make it a fixed constant, but it
@@ -731,7 +737,7 @@ void mp_raw_code_save(mp_raw_code_t *rc, mp_print_t *print) {
         #endif
     };
     if (mp_raw_code_has_native(rc)) {
-        header[2] |= MPY_FEATURE_ENCODE_ARCH(MPY_FEATURE_ARCH);
+        header[2] |= MPY_FEATURE_ENCODE_ARCH(MPY_FEATURE_ARCH_DYNAMIC);
     }
     mp_print_bytes(print, header, sizeof(header));
     mp_print_uint(print, QSTR_WINDOW_SIZE);