diff --git a/Documentation/acpi/DSD-properties-rules.txt b/Documentation/acpi/DSD-properties-rules.txt
new file mode 100644
index 0000000000000..3e4862bdad98c
--- /dev/null
+++ b/Documentation/acpi/DSD-properties-rules.txt
@@ -0,0 +1,97 @@
+_DSD Device Properties Usage Rules
+----------------------------------
+
+Properties, Property Sets and Property Subsets
+----------------------------------------------
+
+The _DSD (Device Specific Data) configuration object, introduced in ACPI 5.1,
+allows any type of device configuration data to be provided via the ACPI
+namespace.  In principle, the format of the data may be arbitrary, but it has to
+be identified by a UUID which must be recognized by the driver processing the
+_DSD output.  However, there are generic UUIDs defined for _DSD recognized by
+the ACPI subsystem in the Linux kernel which automatically processes the data
+packages associated with them and makes those data available to device drivers
+as "device properties".
+
+A device property is a data item consisting of a string key and a value (of a
+specific type) associated with it.
+
+In the ACPI _DSD context it is an element of the sub-package following the
+generic Device Properties UUID in the _DSD return package as specified in the
+Device Properties UUID definition document [1].
+
+It also may be regarded as the definition of a key and the associated data type
+that can be returned by _DSD in the Device Properties UUID sub-package for a
+given device.
+
+A property set is a collection of properties applicable to a hardware entity
+like a device.  In the ACPI _DSD context it is the set of all properties that
+can be returned in the Device Properties UUID sub-package for the device in
+question.
+
+Property subsets are nested collections of properties.  Each of them is
+associated with an additional key (name) allowing the subset to be referred
+to as a whole (and to be treated as a separate entity).  The canonical
+representation of property subsets is via the mechanism specified in the
+Hierarchical Properties Extension UUID definition document [2].
+
+Property sets may be hierarchical.  That is, a property set may contain
+multiple property subsets that each may contain property subsets of its
+own and so on.
+
+General Validity Rule for Property Sets
+---------------------------------------
+
+Valid property sets must follow the guidance given by the Device Properties UUID
+definition document [1].
+
+_DSD properties are intended to be used in addition to, and not instead of, the
+existing mechanisms defined by the ACPI specification.  Therefore, as a rule,
+they should only be used if the ACPI specification does not make direct
+provisions for handling the underlying use case.  It generally is invalid to
+return property sets which do not follow that rule from _DSD in data packages
+associated with the Device Properties UUID.
+
+Additional Considerations
+-------------------------
+
+There are cases in which, even if the general rule given above is followed in
+principle, the property set may still not be regarded as a valid one.
+
+For example, that applies to device properties which may cause kernel code
+(either a device driver or a library/subsystem) to access hardware in a way
+possibly leading to a conflict with AML methods in the ACPI namespace.  In
+particular, that may happen if the kernel code uses device properties to
+manipulate hardware normally controlled by ACPI methods related to power
+management, like _PSx and _DSW (for device objects) or _ON and _OFF (for power
+resource objects), or by ACPI device disabling/enabling methods, like _DIS and
+_SRS.
+
+In all cases in which kernel code may do something that will confuse AML as a
+result of using device properties, the device properties in question are not
+suitable for the ACPI environment and consequently they cannot belong to a valid
+property set.
+
+Property Sets and Device Tree Bindings
+--------------------------------------
+
+It often is useful to make _DSD return property sets that follow Device Tree
+bindings.
+
+In those cases, however, the above validity considerations must be taken into
+account in the first place and returning invalid property sets from _DSD must be
+avoided.  For this reason, it may not be possible to make _DSD return a property
+set following the given DT binding literally and completely.  Still, for the
+sake of code re-use, it may make sense to provide as much of the configuration
+data as possible in the form of device properties and complement that with an
+ACPI-specific mechanism suitable for the use case at hand.
+
+In any case, property sets following DT bindings literally should not be
+expected to automatically work in the ACPI environment regardless of their
+contents.
+
+References
+----------
+
+[1] http://www.uefi.org/sites/default/files/resources/_DSD-device-properties-UUID.pdf
+[2] http://www.uefi.org/sites/default/files/resources/_DSD-hierarchical-data-extension-UUID-v1.1.pdf
diff --git a/Documentation/acpi/enumeration.txt b/Documentation/acpi/enumeration.txt
index a91ec5af52df2..209a5eba6b871 100644
--- a/Documentation/acpi/enumeration.txt
+++ b/Documentation/acpi/enumeration.txt
@@ -415,3 +415,12 @@ the "compatible" property in the _DSD or a _CID as long as one of their
 ancestors provides a _DSD with a valid "compatible" property.  Such device
 objects are then simply regarded as additional "blocks" providing hierarchical
 configuration information to the driver of the composite ancestor device.
+
+However, PRP0001 can only be returned from either _HID or _CID of a device
+object if all of the properties returned by the _DSD associated with it (either
+the _DSD of the device object itself or the _DSD of its ancestor in the
+"composite device" case described above) can be used in the ACPI environment.
+Otherwise, the _DSD itself is regarded as invalid and therefore the "compatible"
+property returned by it is meaningless.
+
+Refer to DSD-properties-rules.txt for more information.
diff --git a/drivers/acpi/device_sysfs.c b/drivers/acpi/device_sysfs.c
index 7b2c48fde4e2b..24418932612ee 100644
--- a/drivers/acpi/device_sysfs.c
+++ b/drivers/acpi/device_sysfs.c
@@ -52,7 +52,7 @@ struct acpi_data_node_attr {
 
 static ssize_t data_node_show_path(struct acpi_data_node *dn, char *buf)
 {
-	return acpi_object_path(dn->handle, buf);
+	return dn->handle ? acpi_object_path(dn->handle, buf) : 0;
 }
 
 DATA_NODE_ATTR(path);
@@ -105,10 +105,10 @@ static void acpi_expose_nondev_subnodes(struct kobject *kobj,
 		init_completion(&dn->kobj_done);
 		ret = kobject_init_and_add(&dn->kobj, &acpi_data_node_ktype,
 					   kobj, "%s", dn->name);
-		if (ret)
-			acpi_handle_err(dn->handle, "Failed to expose (%d)\n", ret);
-		else
+		if (!ret)
 			acpi_expose_nondev_subnodes(&dn->kobj, &dn->data);
+		else if (dn->handle)
+			acpi_handle_err(dn->handle, "Failed to expose (%d)\n", ret);
 	}
 }
 
diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c
index 03f5ec11ab319..3afddcd834efd 100644
--- a/drivers/acpi/property.c
+++ b/drivers/acpi/property.c
@@ -41,14 +41,13 @@ static bool acpi_enumerate_nondev_subnodes(acpi_handle scope,
 static bool acpi_extract_properties(const union acpi_object *desc,
 				    struct acpi_device_data *data);
 
-static bool acpi_nondev_subnode_ok(acpi_handle scope,
-				   const union acpi_object *link,
-				   struct list_head *list)
+static bool acpi_nondev_subnode_extract(const union acpi_object *desc,
+					acpi_handle handle,
+					const union acpi_object *link,
+					struct list_head *list)
 {
-	struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
 	struct acpi_data_node *dn;
-	acpi_handle handle;
-	acpi_status status;
+	bool result;
 
 	dn = kzalloc(sizeof(*dn), GFP_KERNEL);
 	if (!dn)
@@ -58,43 +57,75 @@ static bool acpi_nondev_subnode_ok(acpi_handle scope,
 	dn->fwnode.type = FWNODE_ACPI_DATA;
 	INIT_LIST_HEAD(&dn->data.subnodes);
 
-	status = acpi_get_handle(scope, link->package.elements[1].string.pointer,
-				 &handle);
-	if (ACPI_FAILURE(status))
-		goto fail;
+	result = acpi_extract_properties(desc, &dn->data);
 
-	status = acpi_evaluate_object_typed(handle, NULL, NULL, &buf,
-					    ACPI_TYPE_PACKAGE);
-	if (ACPI_FAILURE(status))
-		goto fail;
+	if (handle) {
+		acpi_handle scope;
+		acpi_status status;
 
-	if (acpi_extract_properties(buf.pointer, &dn->data))
-		dn->handle = handle;
+		/*
+		 * The scope for the subnode object lookup is the one of the
+		 * namespace node (device) containing the object that has
+		 * returned the package.  That is, it's the scope of that
+		 * object's parent.
+		 */
+		status = acpi_get_parent(handle, &scope);
+		if (ACPI_SUCCESS(status)
+		    && acpi_enumerate_nondev_subnodes(scope, desc, &dn->data))
+			result = true;
+	} else if (acpi_enumerate_nondev_subnodes(NULL, desc, &dn->data)) {
+		result = true;
+	}
 
-	/*
-	 * The scope for the subnode object lookup is the one of the namespace
-	 * node (device) containing the object that has returned the package.
-	 * That is, it's the scope of that object's parent.
-	 */
-	status = acpi_get_parent(handle, &scope);
-	if (ACPI_SUCCESS(status)
-	    && acpi_enumerate_nondev_subnodes(scope, buf.pointer, &dn->data))
+	if (result) {
 		dn->handle = handle;
-
-	if (dn->handle) {
-		dn->data.pointer = buf.pointer;
+		dn->data.pointer = desc;
 		list_add_tail(&dn->sibling, list);
 		return true;
 	}
 
+	kfree(dn);
 	acpi_handle_debug(handle, "Invalid properties/subnodes data, skipping\n");
+	return false;
+}
+
+static bool acpi_nondev_subnode_data_ok(acpi_handle handle,
+					const union acpi_object *link,
+					struct list_head *list)
+{
+	struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
+	acpi_status status;
+
+	status = acpi_evaluate_object_typed(handle, NULL, NULL, &buf,
+					    ACPI_TYPE_PACKAGE);
+	if (ACPI_FAILURE(status))
+		return false;
+
+	if (acpi_nondev_subnode_extract(buf.pointer, handle, link, list))
+		return true;
 
- fail:
 	ACPI_FREE(buf.pointer);
-	kfree(dn);
 	return false;
 }
 
+static bool acpi_nondev_subnode_ok(acpi_handle scope,
+				   const union acpi_object *link,
+				   struct list_head *list)
+{
+	acpi_handle handle;
+	acpi_status status;
+
+	if (!scope)
+		return false;
+
+	status = acpi_get_handle(scope, link->package.elements[1].string.pointer,
+				 &handle);
+	if (ACPI_FAILURE(status))
+		return false;
+
+	return acpi_nondev_subnode_data_ok(handle, link, list);
+}
+
 static int acpi_add_nondev_subnodes(acpi_handle scope,
 				    const union acpi_object *links,
 				    struct list_head *list)
@@ -103,15 +134,37 @@ static int acpi_add_nondev_subnodes(acpi_handle scope,
 	int i;
 
 	for (i = 0; i < links->package.count; i++) {
-		const union acpi_object *link;
+		const union acpi_object *link, *desc;
+		acpi_handle handle;
+		bool result;
 
 		link = &links->package.elements[i];
-		/* Only two elements allowed, both must be strings. */
-		if (link->package.count == 2
-		    && link->package.elements[0].type == ACPI_TYPE_STRING
-		    && link->package.elements[1].type == ACPI_TYPE_STRING
-		    && acpi_nondev_subnode_ok(scope, link, list))
-			ret = true;
+		/* Only two elements allowed. */
+		if (link->package.count != 2)
+			continue;
+
+		/* The first one must be a string. */
+		if (link->package.elements[0].type != ACPI_TYPE_STRING)
+			continue;
+
+		/* The second one may be a string, a reference or a package. */
+		switch (link->package.elements[1].type) {
+		case ACPI_TYPE_STRING:
+			result = acpi_nondev_subnode_ok(scope, link, list);
+			break;
+		case ACPI_TYPE_LOCAL_REFERENCE:
+			handle = link->package.elements[1].reference.handle;
+			result = acpi_nondev_subnode_data_ok(handle, link, list);
+			break;
+		case ACPI_TYPE_PACKAGE:
+			desc = &link->package.elements[1];
+			result = acpi_nondev_subnode_extract(desc, NULL, link, list);
+			break;
+		default:
+			result = false;
+			break;
+		}
+		ret = ret || result;
 	}
 
 	return ret;