I'm guessing that the internal workings of FreePascal's objects are subtly different to those of Delphi and so the two wouldn't be compatible even if they got passed over the app/dll boundary.
I use the dynamic DLLs a lot, so I could say: this *could* work and work well (even if the EXE is compiled in Delphi while DLL is in FReePascal)... BUT. You should pay a lot of attention, since your EXE and your DLL do *have separate memory managers*! (I heard there is a whole way around that, ShareMem, but I never used it so I can't say).

Even something as innocious as passing a string parameter could be your undoing! Not to say about classes. Because each module thinks that it was it who allocated the memory... And in a lot of caes it tries silently to re-allocate it, leading to memory corruption.

So, as a rule of thumb: never use strings and dynamic arrays to communicate between your DLL and your EXE! You can always resort to pointers and integers. In fact, each time I need to pass a string I convert it to PChar, and reconstruct on the receiving end by copying into a string. Seems slow?.. But my engine works like a clock, even with a lot of its operations scattered around the EXE/DLL boundary.

In fact, the only problems I encountered with a half of my engine compiled in Delphi and other half in FreePascal was the exception handling. The app just summoned up a standard windows postmortem dialog instead of reporting the error by itself, as designed.