Git is very powerful; it lets users to manipulate stuffs which are usually abstracted by high-level user interface. So it's possible to extract subprojects in a git repository by git filter-branch. But there are several pitfalls to achieve this purpose. The following is what you should know to extract subprojects in a git repository:

Use --index-filter instead of --tree-filter if it's possible.
Generally, --index-filter is faster than --tree-filter. Because --tree-filter involves working tree while --index-filter deosn't have such overheads. And the overhead easily becomes a big burden even if a project is not so large one (for example, 300 files and 2300 commits).
Use --prune-empty and rebase to level the history.
Some kind of filters generate empty commits. Such commits can be removed from the history by --prune-empty. But --prune-empty keeps merge commits even if the merge commits introduce no change. You can use git rebase {the-root-commit-id} to remove such commits and to level the history as linear one.
Remove unnecessaries first, then rename the rest.
It's necessary to do removing unnecessaries and renaming the rest to extract a subproject. But it's hard to do both of them at once, so use filter-branch twice; remove unnecessaries first, then rename file/directory structure.
Use a whitelist to remove unnecessaries.
The history of a project usually contains renaming of files, so it's hard to remove unnecessaries with a blacklist.
Check whether files to keep were renamed before.
The history of a project usually contains renaming of files, so you have to include the old filenames to keep into a whitelist, as well as the current filenames. To list all names which a file was called ever, use the following command: git log --pretty=oneline --follow --name-only {file} | grep -v ' ' | sort -u