diff --git a/fs/Makefile b/fs/Makefile
index 6155cc4..5983276 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -48,7 +48,8 @@ obj-$(CONFIG_SYSCTL)		+= drop_caches.o
 
 obj-$(CONFIG_FHANDLE)		+= fhandle.o
 obj-$(CONFIG_FS_RICHACL)	+= richacl.o
-richacl-y			:= richacl_base.o richacl_inode.o richacl_xattr.o
+richacl-y			:= richacl_base.o richacl_inode.o \
+				   richacl_xattr.o richacl_compat.o
 
 obj-y				+= quota/
 
diff --git a/fs/richacl_compat.c b/fs/richacl_compat.c
new file mode 100644
index 0000000..2ea6658
--- /dev/null
+++ b/fs/richacl_compat.c
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2006, 2010  Novell, Inc.
+ * Copyright (C) 2015  Red Hat, Inc.
+ * Written by Andreas Gruenbacher <agruen@kernel.org>
+ *
+ * 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, 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.
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/richacl_compat.h>
+
+/**
+ * richacl_prepare  -  allocate richacl being constructed
+ *
+ * Allocate a richacl which can hold @count entries but which is initially
+ * empty.
+ */
+struct richacl *richacl_prepare(struct richacl_alloc *x, unsigned int count)
+{
+	x->acl = richacl_alloc(count, GFP_KERNEL);
+	if (!x->acl)
+		return NULL;
+	x->acl->a_count = 0;
+	x->count = count;
+	return x->acl;
+}
+EXPORT_SYMBOL_GPL(richacl_prepare);
+
+/**
+ * richacl_delete_entry  -  delete an entry in an acl
+ * @x:		acl and number of allocated entries
+ * @ace:	an entry in @x->acl
+ *
+ * Updates @ace so that it points to the entry before the deleted entry
+ * on return. (When deleting the first entry, @ace will point to the
+ * (non-existant) entry before the first entry). This behavior is the
+ * expected behavior when deleting entries while forward iterating over
+ * an acl.
+ */
+void
+richacl_delete_entry(struct richacl_alloc *x, struct richace **ace)
+{
+	void *end = x->acl->a_entries + x->acl->a_count;
+
+	memmove(*ace, *ace + 1, end - (void *)(*ace + 1));
+	(*ace)--;
+	x->acl->a_count--;
+}
+EXPORT_SYMBOL_GPL(richacl_delete_entry);
+
+/**
+ * richacl_insert_entry  -  insert an entry in an acl
+ * @x:		acl and number of allocated entries
+ * @ace:	entry before which the new entry shall be inserted
+ *
+ * Insert a new entry in @x->acl at position @ace and zero-initialize
+ * it.  This may require reallocating @x->acl.
+ */
+int
+richacl_insert_entry(struct richacl_alloc *x, struct richace **ace)
+{
+	if (x->count == x->acl->a_count) {
+		int n = *ace - x->acl->a_entries;
+		struct richacl *acl2;
+
+		acl2 = richacl_alloc(x->acl->a_count + 1, GFP_KERNEL);
+		if (!acl2)
+			return -1;
+		acl2->a_flags = x->acl->a_flags;
+		acl2->a_owner_mask = x->acl->a_owner_mask;
+		acl2->a_group_mask = x->acl->a_group_mask;
+		acl2->a_other_mask = x->acl->a_other_mask;
+		memcpy(acl2->a_entries, x->acl->a_entries,
+		       n * sizeof(struct richace));
+		memcpy(acl2->a_entries + n + 1, *ace,
+		       (x->acl->a_count - n) * sizeof(struct richace));
+		kfree(x->acl);
+		x->acl = acl2;
+		x->count = acl2->a_count;
+		*ace = acl2->a_entries + n;
+	} else {
+		void *end = x->acl->a_entries + x->acl->a_count;
+
+		memmove(*ace + 1, *ace, end - (void *)*ace);
+		x->acl->a_count++;
+	}
+	memset(*ace, 0, sizeof(struct richace));
+	return 0;
+}
+EXPORT_SYMBOL_GPL(richacl_insert_entry);
+
+/**
+ * richacl_append_entry  -  append an entry to an acl
+ * @x:		acl and number of allocated entries
+ *
+ * This may require reallocating @x->acl.
+ */
+struct richace *richacl_append_entry(struct richacl_alloc *x)
+{
+	struct richacl *acl = x->acl;
+	struct richace *ace = acl->a_entries + acl->a_count;
+
+	if (x->count > x->acl->a_count) {
+		acl->a_count++;
+		return ace;
+	}
+	return richacl_insert_entry(x, &ace) ? NULL : ace;
+}
+EXPORT_SYMBOL_GPL(richacl_append_entry);
+
+/**
+ * richace_change_mask  -  set the mask of @ace to @mask
+ * @x:		acl and number of allocated entries
+ * @ace:	entry to modify
+ * @mask:	new mask for @ace
+ *
+ * If @ace is inheritable, a inherit-only ace is inserted before @ace which
+ * includes the inheritable permissions of @ace and the inheritance flags of
+ * @ace are cleared before changing the mask.
+ *
+ * If @mode is 0, the original ace is turned into an inherit-only entry if
+ * there are any inheritable permissions, and removed otherwise.
+ *
+ * The returned @ace points to the modified or inserted effective-only acl
+ * entry if that entry exists, to the entry that has become inheritable-only,
+ * or else to the previous entry in the acl.
+ */
+static int
+richace_change_mask(struct richacl_alloc *x, struct richace **ace,
+			   unsigned int mask)
+{
+	if (mask && (*ace)->e_mask == mask)
+		return 0;
+	if (mask & ~RICHACE_POSIX_ALWAYS_ALLOWED) {
+		if (richace_is_inheritable(*ace)) {
+			if (richacl_insert_entry(x, ace))
+				return -1;
+			memcpy(*ace, *ace + 1, sizeof(struct richace));
+			(*ace)->e_flags |= RICHACE_INHERIT_ONLY_ACE;
+			(*ace)++;
+			richace_clear_inheritance_flags(*ace);
+		}
+		(*ace)->e_mask = mask;
+	} else {
+		if (richace_is_inheritable(*ace))
+			(*ace)->e_flags |= RICHACE_INHERIT_ONLY_ACE;
+		else
+			richacl_delete_entry(x, ace);
+	}
+	return 0;
+}
diff --git a/include/linux/richacl_compat.h b/include/linux/richacl_compat.h
new file mode 100644
index 0000000..a9ff630
--- /dev/null
+++ b/include/linux/richacl_compat.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2015  Red Hat, Inc.
+ * Written by Andreas Gruenbacher <agruenba@redhat.com>
+ *
+ * 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, 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.
+ */
+
+#ifndef __RICHACL_COMPAT_H
+#define __RICHACL_COMPAT_H
+
+#include <linux/richacl.h>
+
+/**
+ * struct richacl_alloc  -  remember how many entries are actually allocated
+ * @acl:	acl with a_count <= @count
+ * @count:	the actual number of entries allocated in @acl
+ *
+ * We pass around this structure while modifying an acl so that we do
+ * not have to reallocate when we remove existing entries followed by
+ * adding new entries.
+ */
+struct richacl_alloc {
+	struct richacl *acl;
+	unsigned int count;
+};
+
+struct richacl *richacl_prepare(struct richacl_alloc *, unsigned int);
+struct richace *richacl_append_entry(struct richacl_alloc *);
+int richacl_insert_entry(struct richacl_alloc *, struct richace **);
+void richacl_delete_entry(struct richacl_alloc *, struct richace **);
+
+#endif  /* __RICHACL_COMPAT_H */
