diff --git a/docs/misc/arm/device-tree/booting.txt b/docs/misc/arm/device-tree/booting.txt
index bbd955e9c2..711a6080b5 100644
--- a/docs/misc/arm/device-tree/booting.txt
+++ b/docs/misc/arm/device-tree/booting.txt
@@ -231,6 +231,23 @@ with the following properties:
     In the future other possible property values might be added to
     enable only selected interfaces.
 
+- xen,tee
+
+    A string property that describes what TEE mediator should be enabled
+    for the domain. Possible property values are:
+
+    - "none" (or missing property value)
+    No TEE will be available in the VM.
+
+    - "OP-TEE"
+    VM will have access to the OP-TEE using classic OP-TEE SMC interface.
+
+    - "FF-A"
+    VM will have access to a TEE using generic FF-A interface.
+
+    In the future other TEE mediators may be added, extending possible
+    values for this property.
+
 - xen,domain-p2m-mem-mb
 
     Optional. A 32-bit integer specifying the amount of megabytes of RAM
diff --git a/xen/arch/arm/dom0less-build.c b/xen/arch/arm/dom0less-build.c
index fb63ec6fd1..13fdd44eef 100644
--- a/xen/arch/arm/dom0less-build.c
+++ b/xen/arch/arm/dom0less-build.c
@@ -15,6 +15,7 @@
 #include <asm/domain_build.h>
 #include <asm/static-memory.h>
 #include <asm/static-shmem.h>
+#include <asm/tee/tee.h>
 
 bool __init is_dom0less_mode(void)
 {
@@ -650,6 +651,10 @@ static int __init prepare_dtb_domU(struct domain *d, struct kernel_info *kinfo)
     if ( ret )
         goto err;
 
+    /* We are making assumption that every mediator sets d->arch.tee */
+    if ( d->arch.tee )
+        tee_make_dtb_node(kinfo->fdt);
+
     /*
      * domain_handle_dtb_bootmodule has to be called before the rest of
      * the device tree is generated because it depends on the value of
@@ -871,6 +876,7 @@ void __init create_domUs(void)
         unsigned int flags = 0U;
         uint32_t val;
         int rc;
+        const char *tee_name;
 
         if ( !dt_device_is_compatible(node, "xen,domain") )
             continue;
@@ -881,6 +887,19 @@ void __init create_domUs(void)
         if ( dt_find_property(node, "xen,static-mem", NULL) )
             flags |= CDF_staticmem;
 
+        tee_name = dt_get_property(node, "xen,tee", NULL);
+        if ( tee_name )
+        {
+            rc = tee_get_type_from_dts(tee_name);
+            if ( rc < 0)
+                panic("Can't enable requested TEE for domain: %d\n", rc);
+            d_cfg.arch.tee_type = rc;
+        }
+        else
+        {
+            d_cfg.arch.tee_type = XEN_DOMCTL_CONFIG_TEE_NONE;
+        }
+
         if ( dt_property_read_bool(node, "direct-map") )
         {
             if ( !(flags & CDF_staticmem) )
diff --git a/xen/arch/arm/include/asm/tee/tee.h b/xen/arch/arm/include/asm/tee/tee.h
index da324467e1..9626667545 100644
--- a/xen/arch/arm/include/asm/tee/tee.h
+++ b/xen/arch/arm/include/asm/tee/tee.h
@@ -36,6 +36,9 @@ struct tee_mediator_ops {
     int (*domain_init)(struct domain *d);
     int (*domain_teardown)(struct domain *d);
 
+    /* Make DTB node that describes TEE. Used when creating a dom0less domain */
+    int (*make_dtb_node)(void *fdt);
+
     /*
      * Called during domain destruction to relinquish resources used
      * by mediator itself. This function can return -ERESTART to indicate
@@ -65,7 +68,9 @@ bool tee_handle_call(struct cpu_user_regs *regs);
 int tee_domain_init(struct domain *d, uint16_t tee_type);
 int tee_domain_teardown(struct domain *d);
 int tee_relinquish_resources(struct domain *d);
+int tee_make_dtb_node(void *fdt);
 uint16_t tee_get_type(void);
+int tee_get_type_from_dts(const char* prop_value);
 
 #define REGISTER_TEE_MEDIATOR(_name, _namestr, _type, _ops)         \
 static const struct tee_mediator_desc __tee_desc_##_name __used     \
@@ -105,6 +110,14 @@ static inline uint16_t tee_get_type(void)
     return XEN_DOMCTL_CONFIG_TEE_NONE;
 }
 
+static inline int tee_get_type_from_dts(const char* prop_value)
+{
+    if ( !strcmp(prop_value, "none") )
+        return XEN_DOMCTL_CONFIG_TEE_NONE;
+
+    return -ENODEV;
+}
+
 #endif  /* CONFIG_TEE */
 
 #endif /* __ARCH_ARM_TEE_TEE_H__ */
diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c
index 0793c1c758..f315d6eef6 100644
--- a/xen/arch/arm/tee/ffa.c
+++ b/xen/arch/arm/tee/ffa.c
@@ -1752,6 +1752,13 @@ err_free_ffa_rx:
     return false;
 }
 
+static int ffa_make_dtb_node(void *fdt)
+{
+	/* FF-A is not configured via dtb */
+
+	return 0;
+}
+
 static const struct tee_mediator_ops ffa_ops =
 {
     .probe = ffa_probe,
@@ -1759,6 +1766,7 @@ static const struct tee_mediator_ops ffa_ops =
     .domain_teardown = ffa_domain_teardown,
     .relinquish_resources = ffa_relinquish_resources,
     .handle_call = ffa_handle_call,
+    .make_dtb_node = ffa_make_dtb_node,
 };
 
 REGISTER_TEE_MEDIATOR(ffa, "FF-A", XEN_DOMCTL_CONFIG_TEE_FFA, &ffa_ops);
diff --git a/xen/arch/arm/tee/optee.c b/xen/arch/arm/tee/optee.c
index 5151bd90ed..5eb5d01813 100644
--- a/xen/arch/arm/tee/optee.c
+++ b/xen/arch/arm/tee/optee.c
@@ -28,6 +28,7 @@
 #include <xen/domain_page.h>
 #include <xen/err.h>
 #include <xen/guest_access.h>
+#include <xen/libfdt/libfdt.h>
 #include <xen/mm.h>
 #include <xen/sched.h>
 
@@ -1722,6 +1723,39 @@ static bool optee_handle_call(struct cpu_user_regs *regs)
     }
 }
 
+static int __init optee_make_dtb_node(void *fdt)
+{
+    int res;
+
+    res = fdt_begin_node(fdt, "firmware");
+    if ( res )
+        return res;
+
+    res = fdt_begin_node(fdt, "optee");
+    if ( res )
+        return res;
+
+    res = fdt_property_string(fdt, "compatible", "linaro,optee-tz");
+    if ( res )
+        return res;
+
+    res = fdt_property_string(fdt, "method", "hvc");
+    if ( res )
+        return res;
+
+    /* end of "optee" */
+    res = fdt_end_node(fdt);
+    if ( res )
+        return res;
+
+    /* end of "firmware" */
+    res = fdt_end_node(fdt);
+    if ( res )
+        return res;
+
+    return 0;
+}
+
 static const struct tee_mediator_ops optee_ops =
 {
     .probe = optee_probe,
@@ -1729,6 +1763,7 @@ static const struct tee_mediator_ops optee_ops =
     .domain_teardown = optee_domain_teardown,
     .relinquish_resources = optee_relinquish_resources,
     .handle_call = optee_handle_call,
+    .make_dtb_node = optee_make_dtb_node,
 };
 
 REGISTER_TEE_MEDIATOR(optee, "OP-TEE", XEN_DOMCTL_CONFIG_TEE_OPTEE, &optee_ops);
diff --git a/xen/arch/arm/tee/tee.c b/xen/arch/arm/tee/tee.c
index ddd17506a9..6388166e17 100644
--- a/xen/arch/arm/tee/tee.c
+++ b/xen/arch/arm/tee/tee.c
@@ -68,6 +68,14 @@ int tee_relinquish_resources(struct domain *d)
     return cur_mediator->ops->relinquish_resources(d);
 }
 
+int tee_make_dtb_node(void *fdt)
+{
+    if ( !cur_mediator )
+        return -ENODEV;
+
+    return cur_mediator->ops->make_dtb_node(fdt);
+}
+
 uint16_t tee_get_type(void)
 {
     if ( !cur_mediator )
@@ -76,6 +84,19 @@ uint16_t tee_get_type(void)
     return cur_mediator->tee_type;
 }
 
+int tee_get_type_from_dts(const char* prop_value)
+{
+    if ( !strcmp(prop_value, "none") )
+        return XEN_DOMCTL_CONFIG_TEE_NONE;
+
+    if ( !cur_mediator )
+        return -ENODEV;
+
+    if ( !strcmp(prop_value, cur_mediator->name) )
+        return cur_mediator->tee_type;
+
+    return -ENODEV;
+}
 
 static int __init tee_init(void)
 {
