diff --git a/drivers/interconnect/core.c b/drivers/interconnect/core.c
index 7b971228df38..01109e335baf 100644
--- a/drivers/interconnect/core.c
+++ b/drivers/interconnect/core.c
@@ -17,12 +17,19 @@
 #include <linux/mutex.h>
 #include <linux/slab.h>
 #include <linux/of.h>
 #include <linux/overflow.h>
 
+struct of_icc_proxy {
+	struct device_node *of_node;
+	struct icc_provider *provider;
+	struct list_head list_node;
+};
+
 static DEFINE_IDR(icc_idr);
 static LIST_HEAD(icc_providers);
+static LIST_HEAD(icc_proxy_list);
 static DEFINE_MUTEX(icc_lock);
 static struct dentry *icc_debugfs_dir;
 
 /**
  * struct icc_req - constraints that are attached to each node
@@ -267,10 +274,61 @@ struct icc_node *of_icc_xlate_onecell(struct of_phandle_args *spec,
 
 	return icc_data->nodes[idx];
 }
 EXPORT_SYMBOL_GPL(of_icc_xlate_onecell);
 
+struct icc_provider *__of_icc_get_provider(struct device_node *np)
+{
+	struct of_icc_proxy *proxy;
+
+	lockdep_assert_held(&icc_lock);
+	list_for_each_entry(proxy, &icc_proxy_list, list_node)
+		if (proxy->of_node == np)
+			return proxy->provider;
+
+	return NULL;
+}
+
+static int __of_icc_add_proxy(struct device_node *np,
+			      struct icc_provider *provider)
+{
+	struct of_icc_proxy *proxy;
+
+	lockdep_assert_held(&icc_lock);
+	proxy = kmalloc(sizeof(*proxy), GFP_KERNEL);
+	if (!proxy)
+		return -ENOMEM;
+	proxy->of_node = np;
+	proxy->provider = provider;
+	list_add_tail(&proxy->list_node, &icc_proxy_list);
+
+	return 0;
+}
+
+/**
+ * of_icc_add_proxy() - Add another device_node for a provider
+ * @np: OF node to alias from
+ * @provider: Interconnect provider to map to
+ *
+ * Make another device_node map to the same provider.
+ *
+ * This lasts until icc_provider_del.
+ */
+int of_icc_add_proxy(struct device_node *np, struct icc_provider *provider)
+{
+	int ret;
+
+	mutex_lock(&icc_lock);
+
+	ret = __of_icc_add_proxy(np, provider);
+
+	mutex_unlock(&icc_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(of_icc_add_proxy);
+
 /**
  * of_icc_get_from_provider() - Look-up interconnect node
  * @spec: OF phandle args to use for look-up
  *
  * Looks for interconnect provider under the node specified by @spec and if
@@ -279,23 +337,22 @@ EXPORT_SYMBOL_GPL(of_icc_xlate_onecell);
  * Returns a valid pointer to struct icc_node on success or ERR_PTR()
  * on failure.
  */
 static struct icc_node *of_icc_get_from_provider(struct of_phandle_args *spec)
 {
-	struct icc_node *node = ERR_PTR(-EPROBE_DEFER);
 	struct icc_provider *provider;
+	struct icc_node *node;
 
 	if (!spec || spec->args_count != 1)
 		return ERR_PTR(-EINVAL);
 
 	mutex_lock(&icc_lock);
-	list_for_each_entry(provider, &icc_providers, provider_list) {
-		if (provider->dev->of_node == spec->np)
-			node = provider->xlate(spec, provider->data);
-		if (!IS_ERR(node))
-			break;
-	}
+	provider = __of_icc_get_provider(spec->np);
+	if (provider)
+		node = provider->xlate(spec, provider->data);
+	else
+		node = ERR_PTR(-EPROBE_DEFER);
 	mutex_unlock(&icc_lock);
 
 	return node;
 }
 
@@ -744,17 +801,26 @@ EXPORT_SYMBOL_GPL(icc_node_del);
  *
  * Return: 0 on success, or an error code otherwise
  */
 int icc_provider_add(struct icc_provider *provider)
 {
+	int ret;
+
 	if (WARN_ON(!provider->set))
 		return -EINVAL;
 	if (WARN_ON(!provider->xlate))
 		return -EINVAL;
 
 	mutex_lock(&icc_lock);
 
+	if (provider->dev) {
+		ret = __of_icc_add_proxy(provider->dev->of_node, provider);
+		if (ret) {
+			mutex_unlock(&icc_lock);
+			return ret;
+		}
+	}
 	INIT_LIST_HEAD(&provider->nodes);
 	list_add_tail(&provider->provider_list, &icc_providers);
 
 	mutex_unlock(&icc_lock);
 
@@ -770,10 +836,12 @@ EXPORT_SYMBOL_GPL(icc_provider_add);
  *
  * Return: 0 on success, or an error code otherwise
  */
 int icc_provider_del(struct icc_provider *provider)
 {
+	struct of_icc_proxy *proxy, *tmp;
+
 	mutex_lock(&icc_lock);
 	if (provider->users) {
 		pr_warn("interconnect provider still has %d users\n",
 			provider->users);
 		mutex_unlock(&icc_lock);
@@ -785,10 +853,16 @@ int icc_provider_del(struct icc_provider *provider)
 		mutex_unlock(&icc_lock);
 		return -EBUSY;
 	}
 
 	list_del(&provider->provider_list);
+	list_for_each_entry_safe(proxy, tmp, &icc_proxy_list, list_node)
+		if (proxy->provider == provider) {
+			list_del(&proxy->list_node);
+			of_node_put(proxy->of_node);
+			kfree(proxy);
+		}
 	mutex_unlock(&icc_lock);
 
 	return 0;
 }
 EXPORT_SYMBOL_GPL(icc_provider_del);
diff --git a/include/linux/interconnect-provider.h b/include/linux/interconnect-provider.h
index b16f9effa555..e6773ecac164 100644
--- a/include/linux/interconnect-provider.h
+++ b/include/linux/interconnect-provider.h
@@ -98,10 +98,11 @@ int icc_link_create(struct icc_node *node, const int dst_id);
 int icc_link_destroy(struct icc_node *src, struct icc_node *dst);
 void icc_node_add(struct icc_node *node, struct icc_provider *provider);
 void icc_node_del(struct icc_node *node);
 int icc_provider_add(struct icc_provider *provider);
 int icc_provider_del(struct icc_provider *provider);
+int of_icc_add_proxy(struct device_node *np, struct icc_provider *provider);
 
 #else
 
 static inline struct icc_node *icc_node_create(int id)
 {
@@ -138,8 +139,14 @@ static inline int icc_provider_add(struct icc_provider *provider)
 static inline int icc_provider_del(struct icc_provider *provider)
 {
 	return -ENOTSUPP;
 }
 
+static inline int of_icc_add_proxy(struct device_node *np,
+				   struct icc_provider *provider)
+{
+	return -ENOTSUPP;
+}
+
 #endif /* CONFIG_INTERCONNECT */
 
 #endif /* __LINUX_INTERCONNECT_PROVIDER_H */
