diff --git a/drivers/base/Makefile b/drivers/base/Makefile
index b8ff678fdae9..62695fdcd32f 100644
--- a/drivers/base/Makefile
+++ b/drivers/base/Makefile
@@ -12,7 +12,7 @@ obj-y			+= power/
 obj-$(CONFIG_ISA_BUS_API)	+= isa.o
 obj-y				+= firmware_loader/
 obj-$(CONFIG_NUMA)	+= node.o
-obj-$(CONFIG_HMS)	+= hms.o hms-target.o hms-initiator.o hms-link.o
+obj-$(CONFIG_HMS)	+= hms.o hms-target.o hms-initiator.o hms-link.o hms-bridge.o
 obj-$(CONFIG_MEMORY_HOTPLUG_SPARSE) += memory.o
 ifeq ($(CONFIG_SYSFS),y)
 obj-$(CONFIG_MODULES)	+= module.o
diff --git a/drivers/base/hms-bridge.c b/drivers/base/hms-bridge.c
new file mode 100644
index 000000000000..64732e923fba
--- /dev/null
+++ b/drivers/base/hms-bridge.c
@@ -0,0 +1,197 @@
+/*
+ * Copyright 2018 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * Authors:
+ * Jérôme Glisse <jglisse@redhat.com>
+ */
+/* Heterogeneous memory system (HMS) see Documentation/vm/hms.rst */
+#include <linux/capability.h>
+#include <linux/topology.h>
+#include <linux/uaccess.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/hms.h>
+
+
+static inline struct hms_bridge *hms_object_to_bridge(struct hms_object *object)
+{
+	if (object == NULL)
+		return NULL;
+
+	if (object->type != HMS_BRIDGE)
+		return NULL;
+	return container_of(object, struct hms_bridge, object);
+}
+
+static inline struct hms_bridge *device_to_hms_bridge(struct device *device)
+{
+	if (device == NULL)
+		return NULL;
+
+	return hms_object_to_bridge(to_hms_object(device));
+}
+
+struct hms_bridge *hms_bridge_find_locked(unsigned uid)
+{
+	struct hms_object *object = hms_object_find_locked(uid);
+	struct hms_bridge *bridge;
+
+	bridge = hms_object_to_bridge(object);
+	if (bridge)
+		return bridge;
+	hms_object_put(object);
+	return NULL;
+}
+
+struct hms_bridge *hms_bridge_find(unsigned uid)
+{
+	struct hms_object *object = hms_object_find(uid);
+	struct hms_bridge *bridge;
+
+	bridge = hms_object_to_bridge(object);
+	if (bridge)
+		return bridge;
+	hms_object_put(object);
+	return NULL;
+}
+
+static void hms_bridge_release(struct device *device)
+{
+	struct hms_bridge *bridge = device_to_hms_bridge(device);
+
+	hms_object_put(&bridge->linka->object);
+	hms_object_put(&bridge->linkb->object);
+	hms_object_release(&bridge->object);
+	kfree(bridge);
+}
+
+static ssize_t hms_bridge_show_uid(struct device *device,
+				   struct device_attribute *attr,
+				   char *buf)
+{
+	struct hms_bridge *bridge = device_to_hms_bridge(device);
+
+	if (bridge == NULL)
+		return -EINVAL;
+
+	return sprintf(buf, "%d\n", bridge->object.uid);
+}
+
+static DEVICE_ATTR(uid, 0444, hms_bridge_show_uid, NULL);
+
+static struct attribute *hms_bridge_attrs[] = {
+	&dev_attr_uid.attr,
+	NULL
+};
+
+static struct attribute_group hms_bridge_attr_group = {
+	.attrs = hms_bridge_attrs,
+};
+
+static const struct attribute_group *hms_bridge_attr_groups[] = {
+	&hms_bridge_attr_group,
+	NULL,
+};
+
+void hms_bridge_register(struct hms_bridge **bridgep,
+			 struct device *parent,
+			 struct hms_link *linka,
+			 struct hms_link *linkb,
+			 unsigned version)
+{
+	struct hms_bridge *bridge;
+	int ret;
+
+	*bridgep = NULL;
+
+	if (linka == NULL || linkb == NULL)
+		return;
+	linka = hms_object_to_link(hms_object_get(&linka->object));
+	linkb = hms_object_to_link(hms_object_get(&linkb->object));
+	if (linka == NULL || linkb == NULL)
+		goto error;
+
+	bridge = kzalloc(sizeof(*bridge), GFP_KERNEL);
+	if (bridge == NULL)
+		goto error;
+
+	if (hms_object_init(&bridge->object, parent, HMS_BRIDGE, version,
+			    hms_bridge_release, hms_bridge_attr_groups)) {
+		kfree(bridge);
+		goto error;
+	}
+
+	bridge->linka = linka;
+	bridge->linkb = linkb;
+
+	ret = hms_object_link(&bridge->object, &linka->object);
+	if (ret) {
+		hms_bridge_unregister(&bridge);
+		return;
+	}
+
+	ret = hms_object_link(&bridge->object, &linkb->object);
+	if (ret) {
+		hms_bridge_unregister(&bridge);
+		return;
+	}
+
+	*bridgep = bridge;
+	return;
+
+error:
+	hms_object_put(&linka->object);
+	hms_object_put(&linkb->object);
+}
+EXPORT_SYMBOL(hms_bridge_register);
+
+void hms_unbridge_initiator(struct hms_bridge *bridge,
+			    struct hms_initiator *initiator)
+{
+	if (bridge == NULL || initiator == NULL)
+		return;
+	if (bridge->object.type != HMS_BRIDGE)
+		return;
+	if (initiator->object.type != HMS_INITIATOR)
+		return;
+	hms_object_unlink(&bridge->object, &initiator->object);
+}
+EXPORT_SYMBOL(hms_unbridge_initiator);
+
+int hms_bridge_initiator(struct hms_bridge *bridge,
+			 struct hms_initiator *initiator)
+{
+	if (bridge == NULL || initiator == NULL)
+		return -EINVAL;
+	if (bridge->object.type != HMS_BRIDGE)
+		return -EINVAL;
+	if (initiator->object.type != HMS_INITIATOR)
+		return -EINVAL;
+	return hms_object_link(&bridge->object, &initiator->object);
+}
+EXPORT_SYMBOL(hms_bridge_initiator);
+
+void hms_bridge_unregister(struct hms_bridge **bridgep)
+{
+	struct hms_bridge *bridge = *bridgep;
+
+	*bridgep = NULL;
+	if (bridge == NULL)
+		return;
+
+	hms_object_unregister(&bridge->object);
+}
+EXPORT_SYMBOL(hms_bridge_unregister);
diff --git a/include/linux/hms.h b/include/linux/hms.h
index 2a9e49a2d771..511b5363d8f2 100644
--- a/include/linux/hms.h
+++ b/include/linux/hms.h
@@ -115,6 +115,24 @@ void hms_link_register(struct hms_link **linkp, struct device *parent,
 void hms_link_unregister(struct hms_link **linkp);
 
 
+struct hms_bridge {
+	struct hms_object object;
+	struct hms_link *linka;
+	struct hms_link *linkb;
+};
+
+void hms_unbridge_initiator(struct hms_bridge *bridge,
+			    struct hms_initiator *initiator);
+int hms_bridge_initiator(struct hms_bridge *bridge,
+			 struct hms_initiator *initiator);
+void hms_bridge_register(struct hms_bridge **bridgep,
+			 struct device *parent,
+			 struct hms_link *linka,
+			 struct hms_link *linkb,
+			 unsigned version);
+void hms_bridge_unregister(struct hms_bridge **bridgep);
+
+
 int hms_init(void);
 
 
@@ -139,6 +157,12 @@ int hms_init(void);
 #define hms_link_unregister(linkp)
 
 
+#define hms_unbridge_initiator(bridge, initiator)
+#define hms_bridge_initiator(bridge, initiator)
+#define hms_bridge_register(bridgep)
+#define hms_bridge_unregister(bridgep)
+
+
 static inline int hms_init(void)
 {
 	return 0;
