--- a/target/arm/hvf/hvf.c
+++ b/target/arm/hvf/hvf.c
@@ -830,19 +830,27 @@ uint32_t hvf_arm_get_default_ipa_bit_size(void)
 uint32_t hvf_arm_get_default_ipa_bit_size(void)
 {
+#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 130000
     uint32_t default_ipa_size;
     hv_return_t ret = hv_vm_config_get_default_ipa_size(&default_ipa_size);
     assert_hvf_ok(ret);
-
     return default_ipa_size;
+#else
+    /* hv_vm_config_get_default_ipa_size requires macOS 13+; on Monterey M1, default is 36 */
+    return 36;
+#endif
 }
 
 uint32_t hvf_arm_get_max_ipa_bit_size(void)
 {
+#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 130000
     uint32_t max_ipa_size;
     hv_return_t ret = hv_vm_config_get_max_ipa_size(&max_ipa_size);
     assert_hvf_ok(ret);
 
     /*
      * We clamp any IPA size we want to back the VM with to a valid PARange
      * value so the guest doesn't try and map memory outside of the valid range.
      * This logic just clamps the passed in IPA bit size to the first valid
      * PARange value <= to it.
      */
     return round_down_to_parange_bit_size(max_ipa_size);
+#else
+    /* hv_vm_config_get_max_ipa_size requires macOS 13+; on Monterey M1, max is 36 */
+    return 36;
+#endif
 }
 
@@ -883,16 +899,22 @@ hv_return_t hvf_arch_vm_create(MachineState *ms, uint32_t pa_range)
 hv_return_t hvf_arch_vm_create(MachineState *ms, uint32_t pa_range)
 {
     hv_return_t ret;
+#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 130000
     hv_vm_config_t config = hv_vm_config_create();
 
     ret = hv_vm_config_set_ipa_size(config, pa_range);
     if (ret != HV_SUCCESS) {
         goto cleanup;
     }
     chosen_ipa_bit_size = pa_range;
 
     ret = hv_vm_create(config);
 
 cleanup:
     os_release(config);
-
+#else
+    /* hv_vm_config_create/set_ipa_size require macOS 13+; fall back to hv_vm_create(NULL) */
+    chosen_ipa_bit_size = pa_range;
+    ret = hv_vm_create(NULL);
+#endif
     return ret;
 }
