diff --git a/docs/man/xl.cfg.5.pod.in b/docs/man/xl.cfg.5.pod.in
index c99d40307e..77df9c1bdb 100644
--- a/docs/man/xl.cfg.5.pod.in
+++ b/docs/man/xl.cfg.5.pod.in
@@ -1222,7 +1222,7 @@ is given in hexadecimal format and may either be a range, e.g. C<2f8-2ff>
 It is recommended to only use this option for trusted VMs under
 administrator's control.
 
-=item B<iomem=[ "IOMEM_START,NUM_PAGES[@GFN]", "IOMEM_START,NUM_PAGES[@GFN]", ...]>
+=item B<iomem=[ "IOMEM_START,NUM_PAGES[@GFN],MEMORY_POLICY", "IOMEM_START,NUM_PAGES[@GFN][,MEMORY_POLICY]", ...]>
 
 Allow auto-translated domains to access specific hardware I/O memory pages.
 
@@ -1233,6 +1233,14 @@ B<GFN> is not specified, the mapping will be performed using B<IOMEM_START>
 as a start in the guest's address space, therefore performing a 1:1 mapping
 by default.
 All of these values must be given in hexadecimal format.
+B<MEMORY_POLICY> for Arm platforms:
+  - "arm_dev_nGnRE" for Device-nGnRE (Device Memory on Armv7), the default on Arm
+  - "arm_mem_WB" for Outer Shareable Write-Back Cacheable Memory
+They select the stage-2 memory attributes, but note that the resulting
+memory attributes will be a combination of stage-2 and stage-1 memory
+attributes: it will be the strongest between the 2 stages attributes.
+B<MEMORY_POLICY> can be for both Arm and x86 platforms:
+  - "default" which is Uncachable Memory on x86, and arm_dev_nGnRE on Arm
 
 Note that the IOMMU won't be updated with the mappings specified with this
 option. This option therefore should not be used to pass through any
diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h
index 9bacfb97f0..cf12f1d3bd 100644
--- a/tools/libxl/libxl.h
+++ b/tools/libxl/libxl.h
@@ -378,6 +378,11 @@
 #define LIBXL_HAVE_BUILDINFO_BOOTLOADER 1
 #define LIBXL_HAVE_BUILDINFO_BOOTLOADER_ARGS 1
 
+/*
+ * Support specifying memory policy information for memory mappings.
+ */
+#define LIBXL_HAVE_MEMORY_POLICY 1
+
 /*
  * LIBXL_HAVE_EXTENDED_VKB indicates that libxl_device_vkb has extended fields:
  *  - unique_id;
diff --git a/tools/libxl/libxl_arch.h b/tools/libxl/libxl_arch.h
index d624159e53..796c961568 100644
--- a/tools/libxl/libxl_arch.h
+++ b/tools/libxl/libxl_arch.h
@@ -77,6 +77,9 @@ int libxl__arch_extra_memory(libxl__gc *gc,
                              const libxl_domain_build_info *info,
                              uint64_t *out);
 
+_hidden
+int libxl__arch_memory_policy_to_xc(libxl_memory_policy c);
+
 #if defined(__i386__) || defined(__x86_64__)
 
 #define LAPIC_BASE_ADDRESS  0xfee00000
diff --git a/tools/libxl/libxl_arm.c b/tools/libxl/libxl_arm.c
index 141e159043..6b8e7ddb06 100644
--- a/tools/libxl/libxl_arm.c
+++ b/tools/libxl/libxl_arm.c
@@ -1149,6 +1149,20 @@ void libxl__arch_domain_build_info_setdefault(libxl__gc *gc,
     libxl_domain_build_info_init_type(b_info, LIBXL_DOMAIN_TYPE_PVH);
 }
 
+int libxl__arch_memory_policy_to_xc(libxl_memory_policy c)
+{
+    switch (c) {
+    case LIBXL_MEMORY_POLICY_ARM_MEM_WB:
+        return MEMORY_POLICY_ARM_MEM_WB;
+    case LIBXL_MEMORY_POLICY_ARM_DEV_NGNRE:
+        return MEMORY_POLICY_ARM_DEV_nGnRE;
+    case LIBXL_MEMORY_POLICY_DEFAULT:
+        return MEMORY_POLICY_DEFAULT;
+    default:
+        return ERROR_INVAL;
+    }
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/tools/libxl/libxl_create.c b/tools/libxl/libxl_create.c
index 03ce166f4f..9b375cdf69 100644
--- a/tools/libxl/libxl_create.c
+++ b/tools/libxl/libxl_create.c
@@ -1357,6 +1357,7 @@ static void domcreate_launch_dm(libxl__egc *egc, libxl__multidev *multidev,
 
     for (i = 0; i < d_config->b_info.num_iomem; i++) {
         libxl_iomem_range *io = &d_config->b_info.iomem[i];
+        int memory_policy;
 
         LOGD(DEBUG, domid, "iomem %"PRIx64"-%"PRIx64,
              io->start, io->start + io->number - 1);
@@ -1370,9 +1371,16 @@ static void domcreate_launch_dm(libxl__egc *egc, libxl__multidev *multidev,
             ret = ERROR_FAIL;
             goto error_out;
         }
-        ret = xc_domain_memory_mapping(CTX->xch, domid,
+        memory_policy = libxl__arch_memory_policy_to_xc(io->memory_policy);
+        if (memory_policy < 0) {
+            LOGED(ERROR, domid,
+                  "invalid memory policy %u", io->memory_policy);
+            ret = ERROR_FAIL;
+            goto error_out;
+        }
+        ret = xc_domain_mem_map_policy(CTX->xch, domid,
                                        io->gfn, io->start,
-                                       io->number, 1);
+                                       io->number, 1, memory_policy);
         if (ret < 0) {
             LOGED(ERROR, domid,
                   "failed to map to domain iomem range %"PRIx64"-%"PRIx64
diff --git a/tools/libxl/libxl_types.idl b/tools/libxl/libxl_types.idl
index b61399ce36..ad5d9cdae2 100644
--- a/tools/libxl/libxl_types.idl
+++ b/tools/libxl/libxl_types.idl
@@ -272,6 +272,12 @@ libxl_ioport_range = Struct("ioport_range", [
     ("number", uint32),
     ])
 
+libxl_memory_policy = Enumeration("memory_policy", [
+    (0, "default"),
+    (1, "ARM_Dev_nGnRE"),
+    (2, "ARM_Mem_WB"),
+    ], init_val = "LIBXL_MEMORY_POLICY_DEFAULT")
+
 libxl_iomem_range = Struct("iomem_range", [
     # start host frame number to be mapped to the guest
     ("start", uint64),
@@ -279,6 +285,8 @@ libxl_iomem_range = Struct("iomem_range", [
     ("number", uint64),
     # guest frame number used as a start for the mapping
     ("gfn", uint64, {'init_val': "LIBXL_INVALID_GFN"}),
+    # memory_policy of the memory region
+    ("memory_policy", libxl_memory_policy),
     ])
 
 libxl_vga_interface_info = Struct("vga_interface_info", [
diff --git a/tools/libxl/libxl_x86.c b/tools/libxl/libxl_x86.c
index c0f88a7eaa..32c211c3ae 100644
--- a/tools/libxl/libxl_x86.c
+++ b/tools/libxl/libxl_x86.c
@@ -631,6 +631,16 @@ void libxl__arch_domain_build_info_setdefault(libxl__gc *gc,
     libxl_defbool_setdefault(&b_info->acpi, true);
 }
 
+int libxl__arch_memory_policy_to_xc(libxl_memory_policy c)
+{
+    switch (c) {
+    case LIBXL_MEMORY_POLICY_DEFAULT:
+        return MEMORY_POLICY_DEFAULT;
+    default:
+        return ERROR_INVAL;
+    }
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/tools/xl/xl_parse.c b/tools/xl/xl_parse.c
index e105bda2bb..c019bca728 100644
--- a/tools/xl/xl_parse.c
+++ b/tools/xl/xl_parse.c
@@ -1883,6 +1883,7 @@ void parse_config_data(const char *config_source,
         }
         for (i = 0; i < num_iomem; i++) {
             int used;
+            const char *mempolicy;
 
             buf = xlu_cfg_get_listitem (iomem, i);
             if (!buf) {
@@ -1895,11 +1896,30 @@ void parse_config_data(const char *config_source,
                          &b_info->iomem[i].start,
                          &b_info->iomem[i].number, &used,
                          &b_info->iomem[i].gfn, &used);
-            if (ret < 2 || buf[used] != '\0') {
+            if (ret < 2) {
                 fprintf(stderr,
                         "xl: Invalid argument parsing iomem: %s\n", buf);
                 exit(1);
             }
+            mempolicy = &buf[used];
+            if (strlen(mempolicy) > 1) {
+                mempolicy++;
+                if (!strcmp(mempolicy, "arm_dev_nGnRE"))
+                    b_info->iomem[i].memory_policy =
+                        LIBXL_MEMORY_POLICY_ARM_DEV_NGNRE;
+                else if (!strcmp(mempolicy, "arm_mem_WB"))
+                    b_info->iomem[i].memory_policy =
+                        LIBXL_MEMORY_POLICY_ARM_MEM_WB;
+                else if (!strcmp(mempolicy, "default"))
+                    b_info->iomem[i].memory_policy =
+                        LIBXL_MEMORY_POLICY_DEFAULT;
+                else {
+                    fprintf(stderr,
+                            "xl: Invalid iomem memory policy parameter: %s\n",
+                            mempolicy);
+                    exit(1);
+                }
+            }
         }
     }
 
