diff --git a/src/HtmlUtils.js b/src/HtmlUtils.js
index 6ede36ee81..7fc6908caf 100644
--- a/src/HtmlUtils.js
+++ b/src/HtmlUtils.js
@@ -2,6 +2,7 @@
 Copyright 2015, 2016 OpenMarket Ltd
 Copyright 2017, 2018 New Vector Ltd
 Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
+Copyright 2019 The Matrix.org Foundation C.I.C.
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
@@ -33,6 +34,7 @@ import url from 'url';
 
 import EMOJIBASE from 'emojibase-data/en/compact.json';
 import EMOJIBASE_REGEX from 'emojibase-regex';
+import {tryTransformPermalinkToLocalHref} from "./utils/permalinks/RoomPermalinkCreator";
 
 linkifyMatrix(linkify);
 
@@ -158,30 +160,10 @@ const transformTags = { // custom to matrix
         if (attribs.href) {
             attribs.target = '_blank'; // by default
 
-            let m;
-            // FIXME: horrible duplication with linkify-matrix
-            m = attribs.href.match(linkifyMatrix.VECTOR_URL_PATTERN);
-            if (m) {
-                attribs.href = m[1];
+            const transformed = tryTransformPermalinkToLocalHref(attribs.href);
+            if (transformed !== attribs.href || attribs.href.match(linkifyMatrix.VECTOR_URL_PATTERN)) {
+                attribs.href = transformed;
                 delete attribs.target;
-            } else {
-                m = attribs.href.match(linkifyMatrix.MATRIXTO_URL_PATTERN);
-                if (m) {
-                    const entity = m[1];
-                    switch (entity[0]) {
-                        case '@':
-                            attribs.href = '#/user/' + entity;
-                            break;
-                        case '+':
-                            attribs.href = '#/group/' + entity;
-                            break;
-                        case '#':
-                        case '!':
-                            attribs.href = '#/room/' + entity;
-                            break;
-                    }
-                    delete attribs.target;
-                }
             }
         }
         attribs.rel = 'noopener'; // https://mathiasbynens.github.io/rel-noopener/
diff --git a/src/linkify-matrix.js b/src/linkify-matrix.js
index 2d72b7fb41..0bed83ce84 100644
--- a/src/linkify-matrix.js
+++ b/src/linkify-matrix.js
@@ -1,5 +1,6 @@
 /*
 Copyright 2015, 2016 OpenMarket Ltd
+Copyright 2019 The Matrix.org Foundation C.I.C.
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
@@ -15,6 +16,7 @@ limitations under the License.
 */
 
 import {baseUrl} from "./utils/permalinks/SpecPermalinkConstructor";
+import {tryTransformPermalinkToLocalHref} from "./utils/permalinks/RoomPermalinkCreator";
 
 function matrixLinkify(linkify) {
     // Text tokens
@@ -225,20 +227,8 @@ matrixLinkify.options = {
             case 'roomalias':
             case 'userid':
             case 'groupid':
-                return matrixLinkify.MATRIXTO_BASE_URL + '/#/' + href;
             default: {
-                // FIXME: horrible duplication with HtmlUtils' transform tags
-                let m = href.match(matrixLinkify.VECTOR_URL_PATTERN);
-                if (m) {
-                    return m[1];
-                }
-                m = href.match(matrixLinkify.MATRIXTO_URL_PATTERN);
-                if (m) {
-                    const entity = m[1];
-                    if (matrixToEntityMap[entity[0]]) return matrixToEntityMap[entity[0]] + entity;
-                }
-
-                return href;
+                return tryTransformPermalinkToLocalHref(href);
             }
         }
     },
@@ -249,8 +239,8 @@ matrixLinkify.options = {
 
     target: function(href, type) {
         if (type === 'url') {
-            if (href.match(matrixLinkify.VECTOR_URL_PATTERN) ||
-                href.match(matrixLinkify.MATRIXTO_URL_PATTERN)) {
+            const transformed = tryTransformPermalinkToLocalHref(href);
+            if (transformed !== href || href.match(matrixLinkify.VECTOR_URL_PATTERN)) {
                 return null;
             } else {
                 return '_blank';
diff --git a/src/utils/permalinks/RoomPermalinkCreator.js b/src/utils/permalinks/RoomPermalinkCreator.js
index 82f92c80c9..489a6c8b82 100644
--- a/src/utils/permalinks/RoomPermalinkCreator.js
+++ b/src/utils/permalinks/RoomPermalinkCreator.js
@@ -20,6 +20,7 @@ import utils from 'matrix-js-sdk/lib/utils';
 import SpecPermalinkConstructor, {baseUrl as matrixtoBaseUrl} from "./SpecPermalinkConstructor";
 import PermalinkConstructor, {PermalinkParts} from "./PermalinkConstructor";
 import RiotPermalinkConstructor from "./RiotPermalinkConstructor";
+import * as matrixLinkify from "../../linkify-matrix";
 
 const SdkConfig = require("../../SdkConfig");
 
@@ -286,6 +287,40 @@ export function isPermalinkHost(host: string): boolean {
     return getPermalinkConstructor().isPermalinkHost(host);
 }
 
+/**
+ * Transforms a permalink (or possible permalink) into a local URL if possible. If
+ * the given permalink is found to not be a permalink, it'll be returned unaltered.
+ */
+export function tryTransformPermalinkToLocalHref(permalink: string): string {
+    if (!permalink.startsWith("http:") && !permalink.startsWith("https:")) {
+        return permalink;
+    }
+
+    let m = permalink.match(matrixLinkify.VECTOR_URL_PATTERN);
+    if (m) {
+        return m[1];
+    }
+
+    // A bit of a hack to convert permalinks of unknown origin to Riot links
+    try {
+        const permalinkParts = parsePermalink(permalink);
+        if (permalinkParts) {
+            if (permalinkParts.roomIdOrAlias) {
+                const eventIdPart = permalinkParts.eventId ? `/${permalinkParts.eventId}` : '';
+                permalink = `#/room/${permalinkParts.roomIdOrAlias}${eventIdPart}`;
+            } else if (permalinkParts.groupId) {
+                permalink = `#/group/${permalinkParts.groupId}`;
+            } else if (permalinkParts.userId) {
+                permalink = `#/user/${permalinkParts.userId}`;
+            } // else not a valid permalink for our purposes - do not handle
+        }
+    } catch (e) {
+        // Not an href we need to care about
+    }
+
+    return permalink;
+}
+
 function getPermalinkConstructor(): PermalinkConstructor {
     const riotPrefix = SdkConfig.get()['permalinkPrefix'];
     if (riotPrefix && riotPrefix !== matrixtoBaseUrl) {